// import org.scalatest.{Matchers, FlatSpec}
// import scala.util.Random

// import chisel3._
// import chiseltest._
// import chisel3.util.log2Up

// import comlib.chisel._
// import comlib.chisel.util._

// /** Test
//   *
//   *
//   */
// class ReduceSpec extends FlatSpec with ChiselScalatestTester with Matchers {

//   behavior of "Reduce"

//   val rnd = new Random

//   class ReduceTest(dly:Int, stage:Int) extends Module {
//     val io = IO(new Bundle{
//       val ins = Input(Vec(32, UInt(8.W)))
//       val vld = Output(Bool())
//       val idx = Output(UInt())
//       val key = Output(UInt())
//     })
    
//     val idx_size = log2Up( io.ins.size )

//     // val (ret, _ffs) = io.ins.zipWithIndex.map{ case(v,i)=>Comparator(v=/=0.U, v, i.U(idx_size.W)) }.reduceTree(_ max _, dly, stage)
//     val (cnt, wrap) = chisel3.util.Counter(true.B, 6)
//     val ss = io.ins
//       .zipWithIndex.map{ case(v,i)=>Comparator(v=/=0.U, v, i.U(idx_size.W)) }
//       .groupVec( 6, Comparator(false.B, 0.U(8.W), 0.U(idx_size.W)) )
//       .apply( cnt )

//     val (cmp_ret, _ffs) = ss
//       .toSeq
//       .reduceTree( _ max _, dly, stage )

//     chisel3.printf(p"Current cmp_ret is: ${cmp_ret}")

//     var ret = reduce.reduceSerial( (a:ComparatorWithValid[UInt], b:ComparatorWithValid[UInt])=>a max b, cmp_ret, wrap )

//     chisel3.printf(p" |  Final ret is: ${ret} | ${ss}\n")

//     io.vld := ret.vld
//     io.idx := ret.data
//     io.key := ret.key

//     def ffs = _ffs + 7  // serial slotNum + serial lockStage
//   }


//   it should "Basic increase test" ignore {

//     val dly = rnd.nextInt( 3 )
//     val stage = if(dly==0) 1 else rnd.nextInt( dly ) + 1

//     test( new ReduceTest(dly, stage) ){ dut =>

//       val ffs = dut.ffs

//       // 0->32 test
//       for( i <- 0 until 32 ) dut.io.ins(i).poke( i.U )
//       dut.clock.step( ffs )
//       dut.io.vld.expect( true.B, s"Step increase test error when ffs=${ffs} stage=${dly}" )
//       dut.io.idx.expect( 31.U )
//       dut.io.key.expect( 31.U )

//     }
//   }


//   it should "support max search function" in {

//     val dly = 2
//     val stage = 1

//     test( new ReduceTest(dly, stage) ){ dut =>

//       val ffs = dut.ffs

//         // Ramdom Test
//       for( slot <- 0 until 1 ){
//         val ins = ( 0 until 32 ).map{ case _ => rnd.nextInt(255)+1 }
//         for( i <- 0 until 32 ) dut.io.ins(i).poke( ins(i).U )
//         val max = ins.toArray.max

//         dut.clock.step( ffs )

//         dut.io.vld.expect( true.B, s"Random test error when ffs=${ffs} stage=${dly}" )
//         dut.io.key.expect( max.U, s"Random test error when ffs=${ffs} stage=${dly}" )
//         dut.io.idx.expect( ins.indexOf(max).U, s"Random test error when ffs=${ffs} stage=${dly}" )
//       }
//     }
//   }


//     it should "support Serial Reduce Feature" in {

//         class MyTest(op:(UInt,UInt)=>UInt, lock:Boolean) extends Module {
//             val io = IO(new Bundle{
//                 val ins = Input(UInt(8.W))
//                 val start = Input(Bool())
//                 val out = Output(UInt())
//             })

//             io.out := reduce.reduceSerial( op, io.ins, io.start, lock )
//         }

//         def max(a:UInt, b:UInt) = Mux(a>=b, a, b)
//         val lock = rnd.nextInt(1) == 0

//         test( new MyTest(max, lock) ){ dut =>

//             var start = true
//             var maxValue = 0

//             for( slot <- 0 until 100 ){

//                 val in = rnd.nextInt(256)

//                 dut.io.ins.poke( in.U )
//                 dut.io.start.poke( start.B )

//                 dut.clock.step( if(lock) 1 else 0 )

//                 maxValue = if( in > maxValue || start ) in else maxValue
                
//                 dut.io.out.expect( maxValue.U )

//                 dut.clock.step( if(lock) 0 else 1 )

//                 start = rnd.nextInt(1) == 0
//             }

//         }

//     }

// }